home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / dosrcss.zip / RCSFNMS.C < prev    next >
C/C++ Source or Header  |  1990-07-18  |  35KB  |  1,036 lines

  1. /*
  2.  *                     RCS file name handling
  3.  */
  4. #ifndef lint
  5.  static char
  6.  rcsid[]= "$Id: rcsfnms.c,v 5.5 90/07/16 21:30:57 lfk Release $ Purdue CS";
  7. #endif
  8. /****************************************************************************
  9.  *                     creation and deletion of semaphorefile,
  10.  *                     creation of temporary filenames and cleanup()
  11.  *                     pairing of RCS file names and working file names.
  12.  *                     Testprogram: define PAIRTEST
  13.  ****************************************************************************
  14.  */
  15.  
  16. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  17.    Distributed under license by the Free Software Foundation, Inc.
  18.  
  19. This file is part of RCS.
  20.  
  21. RCS is free software; you can redistribute it and/or modify
  22. it under the terms of the GNU General Public License as published by
  23. the Free Software Foundation; either version 1, or (at your option)
  24. any later version.
  25.  
  26. RCS is distributed in the hope that it will be useful,
  27. but WITHOUT ANY WARRANTY; without even the implied warranty of
  28. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  29. GNU General Public License for more details.
  30.  
  31. You should have received a copy of the GNU General Public License
  32. along with RCS; see the file COPYING.  If not, write to
  33. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  34.  
  35. Report problems and direct all questions to:
  36.  
  37.     rcs-bugs@cs.purdue.edu
  38.  
  39. */
  40.  
  41.  
  42.  
  43.  
  44. /* $Log:    rcsfnms.c,v $
  45.  * Revision 5.5  90/07/16  21:30:57  lfk
  46.  * fixed a number of mistakes in the MKS/DOS filenaming stuff
  47.  * 
  48.  * Revision 5.4  90/07/15  23:42:35  lfk
  49.  * Fixed one last '\\' versus '/' problem
  50.  * 
  51.  * Revision 5.3  90/07/15  20:25:06  lfk
  52.  * Most major fixes added between rev 5.1 and rev 5.5:
  53.  *     signals fixed so they work on MS-DOS
  54.  *     Added MKS arguments code so argv can be large
  55.  *     added code to handle slashes a'la Unix
  56.  *     added more file extensions to system from MS-DOS
  57.  * 
  58.  * Revision 5.2  90/07/15  11:33:42  ROOT_DOS
  59.  * DOS version of RCS 4.0 checked in for MODS
  60.  * by lfk@athena.mit.edu
  61.  * Also update to MSC 6.0
  62.  * 
  63.  * revision 5.2 koya 90/01/24 10:22:39
  64.  * Change path-name handlars.
  65.  * Especially, separator of path names.
  66.  * 
  67.  * revision 5.1 koya 90/01/24 07:05:43
  68.  * Initial revision
  69.  * 
  70.  * Revision 4.8  89/05/01  15:09:41  narten
  71.  * changed getwd to not stat empty directories.
  72.  * 
  73.  * Revision 4.7  88/11/08  12:01:22  narten
  74.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  75.  * 
  76.  * Revision 4.7  88/08/09  19:12:53  eggert
  77.  * Fix troff macro comment leader bug; add Prolog; allow cc -R; remove lint.
  78.  * 
  79.  * Revision 4.6  87/12/18  11:40:23  narten
  80.  * additional file types added from 4.3 BSD version, and SPARC assembler
  81.  * comment character added. Also, more lint cleanups. (Guy Harris)
  82.  * 
  83.  * Revision 4.5  87/10/18  10:34:16  narten
  84.  * Updating version numbers. Changes relative to 1.1 actually relative
  85.  * to verion 4.3
  86.  * 
  87.  * Revision 1.3  87/03/27  14:22:21  jenkins
  88.  * Port to suns
  89.  * 
  90.  * Revision 1.2  85/06/26  07:34:28  svb
  91.  * Comment leader '% ' for '*.tex' files added.
  92.  * 
  93.  * Revision 1.1  84/01/23  14:50:24  kcs
  94.  * Initial revision
  95.  * 
  96.  * Revision 4.3  83/12/15  12:26:48  wft
  97.  * Added check for KDELIM in file names to pairfilenames().
  98.  * 
  99.  * Revision 4.2  83/12/02  22:47:45  wft
  100.  * Added csh, red, and sl file name suffixes.
  101.  * 
  102.  * Revision 4.1  83/05/11  16:23:39  wft
  103.  * Added initialization of Dbranch to InitAdmin(). Canged pairfilenames():
  104.  * 1. added copying of path from workfile to RCS file, if RCS file is omitted;
  105.  * 2. added getting the file status of RCS and working files;
  106.  * 3. added ignoring of directories.
  107.  * 
  108.  * Revision 3.7  83/05/11  15:01:58  wft
  109.  * Added comtable[] which pairs file name suffixes with comment leaders;
  110.  * updated InitAdmin() accordingly.
  111.  * 
  112.  * Revision 3.6  83/04/05  14:47:36  wft
  113.  * fixed Suffix in InitAdmin().
  114.  * 
  115.  * Revision 3.5  83/01/17  18:01:04  wft
  116.  * Added getwd() and rename(); these can be removed by defining
  117.  * V4_2BSD, since they are not needed in 4.2 bsd.
  118.  * Changed sys/param.h to sys/types.h.
  119.  *
  120.  * Revision 3.4  82/12/08  21:55:20  wft
  121.  * removed unused variable.
  122.  *
  123.  * Revision 3.3  82/11/28  20:31:37  wft
  124.  * Changed mktempfile() to store the generated file names.
  125.  * Changed getfullRCSname() to store the file and pathname, and to
  126.  * delete leading "../" and "./".
  127.  *
  128.  * Revision 3.2  82/11/12  14:29:40  wft
  129.  * changed pairfilenames() to handle file.sfx,v; also deleted checkpathnosfx(),
  130.  * checksuffix(), checkfullpath(). Semaphore name generation updated.
  131.  * mktempfile() now checks for nil path; freefilename initialized properly.
  132.  * Added Suffix .h to InitAdmin. Added testprogram PAIRTEST.
  133.  * Moved rmsema, trysema, trydiraccess, getfullRCSname from rcsutil.c to here.
  134.  *
  135.  * Revision 3.1  82/10/18  14:51:28  wft
  136.  * InitAdmin() now initializes StrictLocks=STRICT_LOCKING (def. in rcsbase.h).
  137.  * renamed checkpath() to checkfullpath().
  138.  */
  139.  
  140.  
  141. #include "rcsbase.h"
  142. #include <sys/types.h>
  143. #include <sys/stat.h>
  144. #ifdef MSDOS
  145. #include <direct.h>
  146. #else
  147. #include <sys/dir.h>
  148. #endif /* MSDOS */
  149.  
  150. extern char * rindex();
  151. extern char * mktemp();
  152. extern FILE * fopen();
  153. extern char * getwd();         /* get working directory; forward decl       */
  154. extern int    stat(), fstat();
  155.  
  156. extern FILE * finptr;          /* RCS input file descriptor                 */
  157. extern FILE * frewrite;        /* New RCS file descriptor                   */
  158. extern char * RCSfilename, * workfilename; /* filenames                     */
  159. struct stat RCSstat, workstat; /* file status for RCS file and working file */
  160. int    haveRCSstat,  haveworkstat; /* indicators if status availalble       */
  161.  
  162.  
  163. char tempfilename [NCPFN+10];  /* used for derived file names               */
  164. char sub1filename [NCPPN];     /* used for files path/file.sfx,v            */
  165. char sub2filename [NCPPN];     /* used for files path/RCS/file.sfx,v        */
  166. char semafilename [NCPPN];     /* name of semaphore file                    */
  167. int  madesema;                 /* indicates whether a semaphore file has been set */
  168. char * tfnames[10];            /* temp. file names to be unlinked when finished   */
  169. int  freefilename;             /* index of next free file name in tfnames[]  */
  170.  
  171.  
  172. struct compair {
  173.         char * suffix, * comlead;
  174. };
  175.  
  176. struct compair comtable[] = {
  177. /* comtable pairs each filename suffix with a comment leader. The comment   */
  178. /* leader is placed before each line generated by the $Log keyword. This    */
  179. /* table is used to guess the proper comment leader from the working file's */
  180. /* suffix during initial ci (see InitAdmin()). Comment leaders are needed   */
  181. /* for languages without multiline comments; for others they are optional.  */
  182. /* According to your MSDOS-environment, you change these settlements. !!    */
  183. /* If you can work on UN*X, it is worthwile to keep these.                  */
  184. /* It however, may casue lack of memory on MSDOS                           */ 
  185. /* $Author: lfk $                                                      */
  186.         "",        "# ",        /* default for empty suffix */
  187.         "awk",    "# ",        /* AWK */
  188.         "c",    " * ",        /* C           */
  189. #ifdef ALL
  190.         "c++"    "// "        /* C++ */
  191.         "cc"    "// "        /* C++ */
  192.         "CC"    "// "        /* C++ */
  193.         "C"        "// "        /* C++ */
  194.         "cl",    ";;; ",        /* common lisp */
  195.         "csh",    "# ",        /* shell       */
  196.         "e",    "# ",        /* efl         */
  197.         "el",    "; ",        /* gnulisp     */
  198. #endif
  199.         "f",    "c ",        /* fortran     */
  200.         "h",    " * ",        /* C-header    */
  201.         "ksh",    "# ",        /* korn shell  */
  202.         "l",    " * ",        /* lex NOTE: conflict between lex and franzlisp*/
  203.         "mac",    "; ",        /* macro vms or dec-20 or pdp-11 macro */
  204.         "me",    ".\\\" ",    /* me-macros   t/nroff*/
  205. #ifdef ALL
  206.         "ml",    "; ",        /* mocklisp    */
  207. #endif
  208.         "mm",    ".\\\" ",    /* mm-macros   t/nroff*/
  209.         "ms",    ".\\\" ",    /* ms-macros   t/nroff*/
  210. #ifdef ALL
  211.         "p",    " * ",        /* pascal      */
  212.         "perl",    "# ",        /* L. Wall's Perl */
  213.         "pl",    "% ",        /* prolog      */
  214.         "r",    "# ",        /* ratfor      */
  215.         "red",    "% ",        /* psl/rlisp   */
  216.         "sh",    "# ",        /* shell       */
  217.         "sl",    "% ",        /* psl         */
  218. #endif
  219.         "tex",    "% ",        /* tex           */
  220.         "y",    " * ",        /* yacc        */
  221. #ifdef ALL
  222.         "ye",    " * ",        /* yacc-efl    */
  223.         "yr",    " * ",        /* yacc-ratfor */
  224. #endif
  225. #ifdef sparc
  226.         "s",    "! ",    /* assembler   */
  227. #endif
  228. #ifdef mc68000
  229.         "s",    "| ",    /* assembler   */
  230. #endif
  231. #ifdef pdp11
  232.         "s",    "/ ",    /* assembler   */
  233. #endif
  234. #ifdef vax
  235.         "s",    "# ",    /* assembler   */
  236. #endif
  237. #ifdef MSDOS 
  238.         "asm",    "; ",    /* assembler   */
  239.         "bat",    "REM ",    /* MS-DOS command.com */
  240.         "cxx",    "// ",    /* MS-DOS c++ */
  241.         "fin",    ".\\\" ",    /* for *.fin files on MSDOS */
  242.         "fma",    ".\\\" ",    /* for fma-macors fin on MSDOS */    
  243.         "for",    "c ",    /* MS Fortran */
  244.         "pl",    "# ",    /* L. Wall's Perl for MS-DOS */
  245. #endif /* MSDOS */
  246.         nil,   ""       /* default for unknown suffix; must always be last */
  247. };
  248.  
  249.  
  250. ffclose(fptr)
  251. FILE * fptr;
  252. /* Function: checks ferror(fptr) and aborts the program if there were
  253.  * errors; otherwise closes fptr.
  254.  */
  255. {       if (ferror(fptr) || fclose(fptr)==EOF)
  256.                 faterror("File read or write error; file system full?");
  257. }
  258.  
  259.  
  260. int trysema(RCSname,makesema)
  261. char * RCSname; int makesema;
  262. /* Function: Checks whether a semaphore file exists for RCSname. If yes,
  263.  * returns false. If not, creates one if makesema==true and returns true
  264.  * if successful. If a semaphore file was created, madesema is set to true.
  265.  * The name of the semaphore file is put into variable semafilename.
  266.  */
  267. {
  268. #ifndef MSDOS
  269.         register char * tp, *sp, *lp;
  270.         int fdesc;
  271.  
  272.         sp=RCSname;
  273.         lp = rindex(sp,'/');
  274.         if (lp==0) {
  275.                 semafilename[0]='.'; semafilename[1]='/';
  276.                 tp= &semafilename[2];
  277.         } else {
  278.                 /* copy path */
  279.                 tp=semafilename;
  280.                 do *tp++ = *sp++; while (sp<=lp);
  281.         }
  282.         /*now insert `,' and append file name */
  283.         *tp++ = ',';
  284.         lp = rindex(sp, RCSSEP);
  285.         while (sp<lp) *tp++ = *sp++;
  286.         *tp++ = ','; *tp++ = '\0'; /* will be the same length as RCSname*/
  287.  
  288.         madesema = false;
  289.         if (access(semafilename, 0) == 0) {
  290.                 error("RCS file %s is in use",RCSname);
  291.                 return false;
  292.         }
  293.         if (makesema) {
  294.                 if ((fdesc=creat(semafilename, 000)) == -1) {
  295.                      error("Can't create semaphore file for RCS file %s",RCSname);
  296.                      return false;
  297.                 } else
  298.                      VOID close(fdesc);
  299.                      madesema=true;
  300.         }
  301.         return true;
  302. #else /* NOT MSDOS */
  303.     makesema = true;
  304.     return true;
  305. #endif /* NOT MSDOS */
  306. }
  307.  
  308.  
  309. rmsema()
  310. /* Function: delete the semaphore file if madeseam==true;
  311.  * sets madesema to false.
  312.  */
  313. {
  314. #ifdef MSDOS
  315.     madesema = false ;
  316. #else
  317.         if (madesema) {
  318.                 madesema=false;
  319.                 if (unlink(semafilename) == -1) {
  320.                         error("Can't find semaphore file %s",semafilename);
  321.                 }
  322.         }
  323. #endif /* MSDOS */
  324. }
  325.  
  326. InitCleanup()
  327. {       freefilename =  0;  /* initialize pointer */
  328. }
  329.  
  330.  
  331. cleanup()
  332. /* Function: closes input file and rewrite file.
  333.  * Unlinks files in tfnames[], deletes semaphore file.
  334.  */
  335. {
  336.         register int i;
  337.  
  338.         if (finptr!=NULL)   VOID fclose(finptr);
  339.         if (frewrite!=NULL) VOID fclose(frewrite);
  340.         for (i=0; i<freefilename; i++) {
  341.             if (tfnames[i][0]!='\0')  VOID unlink(tfnames[i]);
  342.         }
  343.         InitCleanup();
  344.         rmsema();
  345. }
  346.  
  347.  
  348. char * mktempfile(fullpath,filename)
  349. register char * fullpath, * filename;
  350. /* Function: Creates a unique filename using the process id and stores it
  351.  * into a free slot in tfnames. The filename consists of the path contained
  352.  * in fullpath concatenated with filename. filename should end in "XXXXXX".
  353.  * Because of storage in tfnames, cleanup() can unlink the file later.
  354.  * freefilename indicates the lowest unoccupied slot in tfnames.
  355.  * Returns a pointer to the filename created.
  356.  * Example use: mktempfile("/tmp/", somefilename)
  357.  */
  358. {
  359.         register char * lastslash, *tp;
  360.         if ((tp=tfnames[freefilename])==nil)
  361.               tp=tfnames[freefilename] = talloc(NCPPN);
  362. #ifdef MSDOS
  363. #    ifdef MKS
  364.         if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) {
  365. #    else
  366.         if (fullpath!=nil && (lastslash=rindex(fullpath,'\\'))!=0) {
  367. #    endif
  368. #else
  369.         if (fullpath!=nil && (lastslash=rindex(fullpath,'/'))!=0) {
  370. #endif /* MSDOS */
  371.                 /* copy path */
  372.                 while (fullpath<=lastslash) *tp++ = *fullpath++;
  373.         }
  374.         while (*tp++ = *filename++);
  375.         return (mktemp(tfnames[freefilename++]));
  376. }
  377.  
  378.  
  379.  
  380.  
  381. char * bindex(sp,c)
  382. register char * sp, c;
  383. /* Function: Finds the last occurrence of character c in string sp
  384.  * and returns a pointer to the character just beyond it. If the
  385.  * character doesn't occur in the string, sp is returned.
  386.  */
  387. {       register char * r;
  388.         r = sp;
  389.         while (*sp) {
  390.                 if (*sp++ == c) r=sp;
  391.         }
  392.         return r;
  393. }
  394.  
  395.  
  396.  
  397.  
  398.  
  399. InitAdmin()
  400. /* function: initializes an admin node */
  401. {       register char * Suffix;
  402.         register int i;
  403.  
  404.         Head=Dbranch=nil; AccessList=nil; Symbols=nil; Locks=nil;
  405.         StrictLocks=STRICT_LOCKING;
  406.  
  407.         /* guess the comment leader from the suffix*/
  408.         Suffix=bindex(workfilename, '.');
  409. #ifdef MSDOS
  410.     Suffix = strlwr( Suffix );
  411. #endif /* MSDOS */
  412.         if (Suffix==workfilename) Suffix= ""; /* empty suffix; will get default*/
  413.         for (i=0;;i++) {
  414.                 if (comtable[i].suffix==nil) {
  415.                         Comment=comtable[i].comlead; /*default*/
  416.                         break;
  417.                 } elsif (strcmp(Suffix,comtable[i].suffix)==0) {
  418.                         Comment=comtable[i].comlead; /*default*/
  419.                         break;
  420.                 }
  421.         }
  422.         Lexinit(); /* Note: if finptr==NULL, reads nothing; only initializes*/
  423. }
  424.  
  425.  
  426.  
  427. char * findpairfile(argc, argv, fname)
  428. int argc; char * argv[], *fname;
  429. /* Function: Given a filename fname, findpairfile scans argv for a pathname
  430.  * ending in fname. If found, returns a pointer to the pathname, and sets
  431.  * the corresponding pointer in argv to nil. Otherwise returns fname.
  432.  * argc indicates the number of entries in argv. Some of them may be nil.
  433.  */
  434. {
  435.         register char * * next, * match;
  436.         register int count;
  437.  
  438.         for (next = argv, count = argc; count>0; next++,count--) {
  439. #ifdef MSDOS
  440. #    ifdef MKS
  441.                 if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) {
  442. #    else
  443.                 if ((*next != nil) && strcmp(bindex(*next,'\\'),fname)==0) {
  444. #    endif
  445. #else
  446.                 if ((*next != nil) && strcmp(bindex(*next,'/'),fname)==0) {
  447. #endif /* MSDOS */
  448.                         /* bindex finds the beginning of the file name stem */
  449.                         match= *next;
  450.                         *next=nil;
  451.                         return match;
  452.                 }
  453.         }
  454.         return fname;
  455. }
  456.  
  457.  
  458. int pairfilenames(argc, argv, mustread, tostdout)
  459. int argc; char ** argv; int mustread, tostdout;
  460. /* Function: Pairs the filenames pointed to by argv; argc indicates
  461.  * how many there are.
  462.  * Places a pointer to the RCS filename into RCSfilename,
  463.  * and a pointer to the name of the working file into workfilename.
  464.  * If both the workfilename and the RCS filename are given, and tostdout
  465.  * is true, a warning is printed.
  466.  *
  467.  * If the working file exists, places its status into workstat and
  468.  * sets haveworkstat to 0; otherwise, haveworkstat is set to -1;
  469.  * Similarly for the RCS file and the variables RCSstat and haveRCSstat.
  470.  *
  471.  * If the RCS file exists, it is opened for reading, the file pointer
  472.  * is placed into finptr, and the admin-node is read in; returns 1.
  473.  * If the RCS file does not exist and mustread==true, an error is printed
  474.  * and 0 returned.
  475.  * If the RCS file does not exist and mustread==false, the admin node
  476.  * is initialized to empty (Head, AccessList, Locks, Symbols, StrictLocks, Dbranch)
  477.  * and -1 returned.
  478.  *
  479.  * 0 is returned on all errors. Files that are directories are errors.
  480.  * Also calls InitCleanup();
  481.  */
  482. {
  483.         register char * sp, * tp;
  484.         char * lastsep, * purefname, * pureRCSname;
  485.         int opened, returncode;
  486. #ifdef MSDOS
  487.     struct stat dirstat;
  488. #endif /* MSDOS */
  489.         char * RCS1;
  490.     char prefdir[NCPPN];
  491.  
  492.  
  493.         if (*argv == nil) return 0; /* already paired filename */
  494.     if (rindex(*argv,KDELIM)!=0) {
  495.         /* KDELIM causes havoc in keyword expansion    */
  496.         error("RCS file name may not contain %c",KDELIM);
  497.         return 0;
  498.     }
  499.         InitCleanup();
  500.  
  501.         /* first check suffix to see whether it is an RCS file or not */
  502. #ifdef MSDOS
  503. #    ifdef MKS
  504.         purefname=bindex(*argv, '/'); /* skip path */
  505. #    else
  506.         purefname=bindex(*argv, '\\'); /* skip path */
  507. #    endif        
  508. #else
  509.         purefname=bindex(*argv, '/'); /* skip path */
  510. #endif /* MSDOS */
  511. #ifdef MSDOS
  512. #    ifdef MKS
  513.     if( ( pureRCSname = strstr( *argv, "rcs/" ) ) != NULL){
  514. #else
  515.     if( ( pureRCSname = strstr( *argv, "RCS\\" ) ) != NULL){
  516. #endif
  517.                 /* RCS file name given*/
  518.         RCS1 = (*argv);
  519.                 /* derive workfilename*/
  520.         sp = purefname; tp=tempfilename;
  521.         while( *sp != '\0' ) *tp++=*sp++; *tp= '\0';
  522.                 workfilename=findpairfile(argc-1,argv+1,tempfilename);
  523.         if( strlen(pureRCSname) > NCPFN + 4 ) {
  524.             /* To avoid, ambiguous file name. eg."RCS\RCS\foo.c" */
  525.             if( strlen(pureRCSname + 4) != (int) NULL ){
  526.                 error("file name %s is ambiguous", RCS1);
  527.                 return 0;
  528.             }
  529.             error("RCS file name %s too long",RCS1);
  530.             return 0;
  531.         }
  532.     } else {
  533.                 /* working file given; now try to find RCS file */
  534.         workfilename=*argv;
  535.         /* derive RCS file name*/
  536. #    ifdef MKS
  537.         strcpy( tempfilename, "rcs/" );
  538. #    else
  539.         strcpy( tempfilename, "RCS\\" );
  540. #    endif
  541.         strcat( tempfilename, purefname );
  542.                 RCS1=findpairfile(argc-1,argv+1,tempfilename);
  543. #    ifdef MKS
  544.         pureRCSname = strstr( RCS1, "rcs/" );
  545. #    else
  546.         pureRCSname = strstr( RCS1, "RCS\\" );
  547. #    endif
  548.                 if (strlen(pureRCSname)>NCPFN+4) {
  549.                         error("working file name %s too long",workfilename);
  550.                         return 0;
  551.                 }
  552.         }
  553. #    ifdef MKS
  554.     if( strchr( workfilename, '/' ) != NULL ){
  555. #    else
  556.     if( strchr( workfilename, '\\' ) != NULL ){
  557. #    endif
  558.         error("Sorry, file name %s confuse RCS", workfilename );
  559.         return 0;
  560.     }
  561. #else /* MSDOS */
  562.         lastsep=rindex(purefname, RCSSEP);
  563.         if (lastsep!= 0 && *(lastsep+1)==RCSSUF && *(lastsep+2)=='\0') {
  564.                 /* RCS file name given*/
  565.                 RCS1=(*argv); pureRCSname=purefname;
  566.                 /* derive workfilename*/
  567.                 sp = purefname; tp=tempfilename;
  568.                 while (sp<lastsep) *tp++ = *sp++; *tp='\0';
  569.                 /* try to find workfile name among arguments */
  570.                 workfilename=findpairfile(argc-1,argv+1,tempfilename);
  571.                 if (strlen(pureRCSname)>NCPFN) {
  572.                         error("RCS file name %s too long",RCS1);
  573.                         return 0;
  574.                 }
  575.         } else {
  576.                 /* working file given; now try to find RCS file */
  577.                 workfilename= *argv;
  578.                 /* derive RCS file name*/
  579.                 sp=purefname; tp=tempfilename;
  580.                 while (*tp++ = *sp++);
  581.                 *(tp-1)=RCSSEP; *tp++=RCSSUF; *tp++='\0';
  582.                 /* Try to find RCS file name among arguments*/
  583.                 RCS1=findpairfile(argc-1,argv+1,tempfilename);
  584.                 pureRCSname=bindex(RCS1, '/');
  585.                 if (strlen(pureRCSname)>NCPFN) {
  586.                         error("working file name %s too long",workfilename);
  587.                         return 0;
  588.                 }
  589.         }
  590. #endif /* MSDOS */
  591.         /* now we have a (tentative) RCS filename in RCS1 and workfilename  */
  592.         /* First, get status of workfilename */
  593.         haveworkstat=stat(workfilename, &workstat);
  594.         if ((haveworkstat==0) && ((workstat.st_mode & S_IFDIR) == S_IFDIR)) {
  595.                 diagnose("Directory %s ignored",workfilename);
  596.                 return 0;
  597.         }
  598.         /* Second, try to find the right RCS file */
  599. #ifdef MSDOS
  600.     RCSfilename=pureRCSname;
  601.     if (pureRCSname != RCS1){
  602.         error("Sorry, file name %s confuse RCS", RCS1);
  603.         return 0;
  604.     }else{
  605.         opened = ( ( finptr=fopen(pureRCSname, "r" ) ) != NULL );
  606.         if(opened){
  607.             returncode = 1;
  608.         }else{
  609.                         if (mustread) {
  610.                 error("Can't find %s",RCSfilename);
  611.                                 return 0;
  612.             }else{
  613.                 if( stat("RCS", &dirstat) == -1 ){
  614.                     error("Can't find RCS subdirectory");
  615.                     return 0;
  616.                 }else{
  617.                     if( !( dirstat.st_mode & S_IFDIR ) ){
  618.                         error("RCS is really directory?");
  619.                         return 0;
  620.                     }else returncode = -1;
  621.                 }
  622.             }
  623.         }
  624.     }
  625. #else /* MSDOS */    
  626.         if (pureRCSname!=RCS1) {
  627.                 /* a path for RCSfile is given; single RCS file to look for */
  628.                 finptr=fopen(RCSfilename=RCS1, "r");
  629.                 if (finptr!=NULL) {
  630.                     returncode=1;
  631.                 } else { /* could not open */
  632.                     if (access(RCSfilename,0)==0) {
  633.                         error("Can't open existing %s", RCSfilename);
  634.                         return 0;
  635.                     }
  636.                     if (mustread) {
  637.                         error("Can't find %s", RCSfilename);
  638.                         return 0;
  639.                     } else {
  640.                         /* initialize if not mustread */
  641.             returncode = -1;
  642.                     }
  643.                 }
  644.         } else {
  645.         /* no path for RCS file name. Prefix it with path of work */
  646.         /* file if RCS file omitted. Make a second name including */
  647.         /* RCSDIR and try to open that one first.                 */
  648.         sub1filename[0]=sub2filename[0]= '\0';
  649.         if (RCS1==tempfilename) {
  650.             /* RCS file name not given; prepend work path */
  651.             sp= *argv; tp= sub1filename;
  652.             while (sp<purefname) *tp++ = *sp ++;
  653.             *tp='\0';
  654.             VOID strcpy(sub2filename,sub1filename); /* second one */
  655.         }
  656.         VOID strcat(sub1filename,RCSDIR);
  657.         VOID strcpy(prefdir,sub1filename); /* preferred directory for RCS file*/
  658.         VOID strcat(sub1filename,RCS1); VOID strcat(sub2filename,RCS1);
  659.  
  660.                 opened=(
  661.         ((finptr=fopen(RCSfilename=sub1filename, "r"))!=NULL) ||
  662.         ((finptr=fopen(RCSfilename=sub2filename,"r"))!=NULL) );
  663.  
  664.                 if (opened) {
  665.                         /* open succeeded */
  666.                         returncode=1;
  667.                 } else {
  668.                         /* open failed; may be read protected */
  669.             if ((access(RCSfilename=sub1filename,0)==0) ||
  670.                 (access(RCSfilename=sub2filename,0)==0)) {
  671.                                 error("Can't open existing %s",RCSfilename);
  672.                                 return 0;
  673.                         }
  674.                         if (mustread) {
  675.                 error("Can't find %s nor %s",sub1filename,sub2filename);
  676.                                 return 0;
  677.                         } else {
  678.                                 /* initialize new file. Put into ./RCS if possible, strip off suffix*/
  679.                 RCSfilename= (access(prefdir,0)==0)?sub1filename:sub2filename;
  680.                                 returncode= -1;
  681.                         }
  682.                 }
  683.         }
  684. #endif /* MSDOS */
  685.         if (returncode == 1) { /* RCS file open */
  686.                 haveRCSstat=fstat(fileno(finptr),&RCSstat);
  687.                 if ((haveRCSstat== 0) && ((RCSstat.st_mode & S_IFDIR) == S_IFDIR)) {
  688.                         diagnose("Directory %s ignored",RCSfilename);
  689.                         return 0;
  690.                 }
  691.                 Lexinit(); getadmin();
  692.         } else {  /* returncode == -1; RCS file nonexisting */
  693.                 haveRCSstat = -1;
  694.                 InitAdmin();
  695.         };
  696.  
  697.         if (tostdout&&
  698.             !(RCS1==tempfilename||workfilename==tempfilename))
  699.                 /*The last term determines whether a pair of        */
  700.                 /* file names was given in the argument list        */
  701.                 warn("Option -p is set; ignoring output file %s",workfilename);
  702.  
  703.         return returncode;
  704. }
  705.  
  706.  
  707. char * getfullRCSname()
  708. /* Function: returns a pointer to the full path name of the RCS file.
  709.  * Calls getwd(), but only once.
  710.  * removes leading "../" and "./".
  711.  */
  712. {       static char pathbuf[NCPPN];
  713.         static char namebuf[NCPPN];
  714.         static int  pathlength;
  715.  
  716.         register char * realname, * lastpathchar;
  717.         register int  dotdotcounter, realpathlength;
  718.  
  719. #ifdef MSDOS    
  720.     /* Treat a full path name containing the drive name */
  721.     /* Added by $Author: lfk $ */
  722. #    ifdef MKS
  723.         if (RCSfilename[1] == ':' && RCSfilename[2] == '/') {
  724. #    else
  725.         if (RCSfilename[1] == ':' && RCSfilename[2] == '\\') {
  726. #    endif
  727. #else
  728.         if (*RCSfilename=='/') {
  729. #endif /* MSDOS */
  730.                 return(RCSfilename);
  731.         } else {
  732.                 if (pathlength==0) { /*call curdir for the first time*/
  733.                     if (getwd(pathbuf)==NULL)
  734.                         faterror("Can't build current directory path");
  735.                     pathlength=strlen(pathbuf);
  736. #ifdef MSDOS    
  737.         /* Generally, a MSDOS path name seems to be like "A:\" */
  738.         /* Added by $Author: lfk $ */
  739. #    ifdef MKS
  740.                     if (!((pathlength==3) && (pathbuf[2]=='/'))) {
  741.                         pathbuf[pathlength++]='/';
  742. #    else
  743.                     if (!((pathlength==3) && (pathbuf[2]=='\\'))) {
  744.                         pathbuf[pathlength++]='\\';
  745. #    endif
  746.                         /* Check needed because some getwd implementations */
  747.                         /* generate "/" for the root.                      */
  748.                     }
  749. #else
  750.                     if (!((pathlength==1) && (pathbuf[0]=='/'))) {
  751.                         pathbuf[pathlength++]='/';
  752.                         /* Check needed because some getwd implementations */
  753.                         /* generate "/" for the root.                      */
  754.                     }
  755. #endif /* MSDOS */
  756.                 }
  757.                 /*the following must be redone since RCSfilename may change*/
  758.                 /* find how many ../ to remvove from RCSfilename */
  759.                 dotdotcounter =0;
  760.                 realname = RCSfilename;
  761. #ifdef MSDOS    /* Chaged '/' to '\\' : By $Author: lfk $ */
  762.                 while( realname[0]=='.' &&
  763. #    ifdef MKS
  764.                       (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){
  765.                         if (realname[1]=='/') {
  766. #    else
  767.                       (realname[1]=='\\'||(realname[1]=='.'&&realname[2]=='\\'))){
  768.                         if (realname[1]=='\\') {
  769. #    endif
  770.                             /* drop leading ./ */
  771.                             realname += 2;
  772.                         } else {
  773.                             /* drop leading ../ and remember */
  774.                             dotdotcounter++;
  775.                             realname += 3;
  776.                         }
  777.                 }
  778. #else
  779.                 while( realname[0]=='.' &&
  780.                       (realname[1]=='/'||(realname[1]=='.'&&realname[2]=='/'))){
  781.                         if (realname[1]=='/') {
  782.                             /* drop leading ./ */
  783.                             realname += 2;
  784.                         } else {
  785.                             /* drop leading ../ and remember */
  786.                             dotdotcounter++;
  787.                             realname += 3;
  788.                         }
  789.                 }
  790. #endif /* MSDOS */
  791.                 /* now remove dotdotcounter trailing directories from pathbuf*/
  792.                 lastpathchar=pathbuf + pathlength-1;
  793.                 while (dotdotcounter>0 && lastpathchar>pathbuf) {
  794.                     /* move pointer backwards over trailing directory */
  795.                     lastpathchar--;
  796. #ifdef MSDOS
  797. #    ifdef MKS
  798.                     if (*lastpathchar=='/') {
  799. #    else
  800.                     if (*lastpathchar=='\\') {
  801. #    endif
  802. #else
  803.                     if (*lastpathchar=='/') {
  804. #endif /* MSDOS */
  805.                         dotdotcounter--;
  806.                     }
  807.                 }
  808.                 if (dotdotcounter>0) {
  809.                     error("Can't generate full path name for RCS file");
  810.                     return RCSfilename;
  811.                 } else {
  812.                     /* build full path name */
  813.                     realpathlength=lastpathchar-pathbuf+1;
  814.                     VOID strncpy(namebuf,pathbuf,realpathlength);
  815.                     VOID strcpy(&namebuf[realpathlength],realname);
  816.                     return(namebuf);
  817.                 }
  818.         }
  819. }
  820.  
  821. /* In MSDOS and (perhaps) OS/2, any directries are writable.     */
  822. /* So, the below check is NON-SENSE !! : $Author: lfk $         */
  823. int trydiraccess(filename)
  824. char * filename;
  825. /* checks write permission in directory of filename and returns
  826.  * true if writable, false otherwise
  827.  */
  828. {
  829.         char pathname[NCPPN];
  830.         register char * tp, *sp, *lp;
  831.  
  832. #ifdef MSDOS
  833.     return true;
  834. #else
  835.         lp = rindex(filename,'/');
  836.         if (lp==0) {
  837.                 /* check current directory */
  838.                 if (access(".",2)==0)
  839.                         return true;
  840.                 else {
  841.                         error("Current directory not writable");
  842.                         return false;
  843.                 }
  844.         }
  845.         /* copy path */
  846.         sp=filename;
  847.         tp=pathname;
  848.         do *tp++ = *sp++; while (sp<=lp);
  849.         *tp='\0';
  850.         if (access(pathname,2)==0)
  851.                 return true;
  852.         else {
  853.                 error("Directory %s not writable", pathname);
  854.                 return false;
  855.         }
  856. #endif /* MSDOS */
  857. }
  858.  
  859.  
  860.  
  861. #ifndef V4_2BSD
  862. /* rename() and getwd() will be provided in bsd 4.2 */
  863.  
  864. #ifndef MSDOS
  865. int rename(from, to)
  866. char * from, *to;
  867. /* Function: renames a file with the name given by from to the name given by to.
  868.  * unlinks the to-file if it already exists. returns -1 on error, 0 otherwise.
  869.  */
  870. {       VOID unlink(to);      /* no need to check return code; will be caught by link*/
  871.                          /* no harm done if file "to" does not exist            */
  872.         if (link(from,to)<0) return -1;
  873.         return(unlink(from));
  874. }
  875.  
  876. #define dot     "."
  877. #define dotdot  ".."
  878.  
  879.  
  880. char * getwd(name)
  881. char * name;
  882. /* Function: places full pathname of current working directory into name and
  883.  * returns name on success, NULL on failure.
  884.  * getwd is an adaptation of pwd. May not return to the current directory on
  885.  * failure.
  886.  */
  887. {
  888.         FILE    *file;
  889.         struct  stat    d, dd;
  890.         char buf[2];    /* to NUL-terminate dir.d_name */
  891.         struct  direct  dir;
  892.  
  893.         int rdev, rino;
  894.         int off;
  895.         register i,j;
  896.  
  897.         name[off= 0] = '/';
  898.         name[1] = '\0';
  899.         buf[0] = '\0';
  900.         if (stat("/", &d)<0) return NULL;
  901.         rdev = d.st_dev;
  902.         rino = d.st_ino;
  903.         for (;;) {
  904.                 if (stat(dot, &d)<0) return NULL;
  905.                 if (d.st_ino==rino && d.st_dev==rdev) {
  906.                         if (name[off] == '/') name[off] = '\0';
  907.                         chdir(name); /*change back to current directory*/
  908.                         return name;
  909.                 }
  910.                 if ((file = fopen(dotdot,"r")) == NULL) return NULL;
  911.                 if (fstat(fileno(file), &dd)<0) goto fail;
  912.                 chdir(dotdot);
  913.                 if(d.st_dev == dd.st_dev) {
  914.                         if(d.st_ino == dd.st_ino) {
  915.                             if (name[off] == '/') name[off] = '\0';
  916.                             chdir(name); /*change back to current directory*/
  917.                             VOID fclose(file);
  918.                             return name;
  919.                         }
  920.                         do {
  921.                             if (fread((char *)&dir, sizeof(dir), 1, file) !=1)
  922.                                 goto fail;
  923.                         } while (dir.d_ino != d.st_ino);
  924.                 }
  925.                 else do {
  926.                         if(fread((char *)&dir, sizeof(dir), 1, file) != 1) {
  927.                             goto fail;
  928.                         }
  929.                         if (dir.d_ino == 0)
  930.                 dd.st_ino = d.st_ino + 1;
  931.                         else if (stat(dir.d_name, &dd) < 0)
  932.                 goto fail;
  933.                 } while(dd.st_ino != d.st_ino || dd.st_dev != d.st_dev);
  934.                 VOID fclose(file);
  935.  
  936.                 /* concatenate file name */
  937.                 i = -1;
  938.                 while (dir.d_name[++i] != 0);
  939.                 for(j=off+1; j>0; --j)
  940.                         name[j+i+1] = name[j];
  941.                 off=i+off+1;
  942.                 name[i+1] = '/';
  943.                 for(--i; i>=0; --i)
  944.                         name[i+1] = dir.d_name[i];
  945.         } /* end for */
  946.  
  947. fail:   VOID fclose(file);
  948.         return NULL;
  949. }
  950. #else /* MSDOS */
  951.  
  952. char *getwd(name)
  953. char    *name;
  954. {
  955.     int a,i;
  956.     (void)getcwd(name, NCPPN);
  957. #ifdef MKS
  958.     strlwr(name);
  959.     a = strlen(name);
  960.     for ( i = 0; i <= a; i++)
  961.         if(name[i] == '\\')
  962.             name[i] = '/';
  963. #endif
  964.     return name;
  965. }
  966. #endif /* MSODS */
  967. #endif
  968. #ifdef MSDOS
  969. char *gettmpdir()
  970. {
  971.     char tp[NCPPN];
  972.     
  973.     strcpy( tp, (char *) getenv("TMP") );
  974.     if( *tp == (char) NULL ) strcpy( tp, "." );
  975.     if( tp[strlen(tp) - 1] != '\\' )
  976.         strcat( tp, "\\" );
  977.     return tp;
  978. }
  979.  
  980. #endif /* MSDOS */
  981.  
  982. #ifdef PAIRTEST
  983. /* test program for pairfilenames() and getfullRCSname() */
  984. char * workfilename, *RCSfilename;
  985. extern int quietflag;
  986.  
  987. main(argc, argv)
  988. int argc; char *argv[];
  989. {
  990.         int result;
  991.         int initflag,tostdout;
  992.         quietflag=tostdout=initflag=false;
  993.         cmdid="pair";
  994.  
  995.         while(--argc, ++argv, argc>=1 && ((*argv)[0] == '-')) {
  996.                 switch ((*argv)[1]) {
  997.  
  998.                 case 'p':       tostdout=true;
  999.                                 break;
  1000.                 case 'i':       initflag=true;
  1001.                                 break;
  1002.                 case 'q':       quietflag=true;
  1003.                                 break;
  1004.                 default:        error("unknown option: %s", *argv);
  1005.                                 break;
  1006.                 }
  1007.         }
  1008.  
  1009.         do {
  1010.                 RCSfilename=workfilename=nil;
  1011.                 result=pairfilenames(argc,argv,!initflag,tostdout);
  1012.                 if (result!=0) {
  1013.                      diagnose("RCSfile: %s; working file: %s",RCSfilename,workfilename);
  1014.                      diagnose("Full RCS file name: %s", getfullRCSname());
  1015.                 }
  1016.                 switch (result) {
  1017.                         case 0: continue; /* already paired file */
  1018.  
  1019.                         case 1: if (initflag) {
  1020.                                     error("RCS file %s exists already",RCSfilename);
  1021.                                 } else {
  1022.                                     diagnose("RCS file %s exists",RCSfilename);
  1023.                                 }
  1024.                                 VOID fclose(finptr);
  1025.                                 break;
  1026.  
  1027.                         case -1:diagnose("RCS file does not exist");
  1028.                                 break;
  1029.                 }
  1030.  
  1031.         } while (++argv, --argc>=1);
  1032.  
  1033. }
  1034. #endif
  1035.  
  1036.